/**
 * Copyright 2008 Hotye Inc.
 */
package craneding.gwt.databean.client.ui.field;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FocusListener;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

import craneding.gwt.databean.client.model.FieldInfo;

/**
 * <h3>Number Field Input</h3>
 * <ul>
 * e.g.
 * <li>byte、Byte</li>
 * <li>short、int、long、Short、Integer、Long</li>
 * <li>float、double、Float、Double</li>
 * </ul>
 * <h3>CSS Style Rules</h3> <ul class='css'> <li>.DataBean-NumberFieldInput{
 * primary style }</li> </ul>
 * 
 * @author crane.ding
 * @version 1.0 2008-12-2
 */
public class NumberFieldInput extends TextBox implements IFieldInput,
		KeyboardListener, FocusListener {

	private static final String REGEX = "[-]?+\\d++";
	private static final String REGEX_POINT = "[-]?+\\d++[.]?+\\d++";
	private FieldInfo fieldInfo;
	private boolean isOnKeyUp = true;// 是否需要在ONKEYUP事件中校验.
	private ValidationPopupPanel validateMsg;
	private String fieldName;

	public NumberFieldInput() {
		addFocusListener(this);
		addKeyboardListener(this);
		setStyleName("DataBean-NumberFieldInput");
	}

	public Object getValue() {
		String text = getText().trim();
		Class<?> clazz = fieldInfo.datatype();
		if (text.length() <= 0) {
			if (FieldInputUtil.isBaseNumberType(clazz))
				return 0;
			else
				return null;
		}
		if (clazz == byte.class || clazz == Byte.class) {
			return new Byte(text);
		}
		if (clazz == short.class || clazz == Short.class) {
			return new Short(text);
		}
		if (clazz == int.class || clazz == Integer.class) {
			return new Integer(text);
		}
		if (clazz == long.class || clazz == Long.class) {
			return new Long(text);
		}
		if (clazz == float.class || clazz == Float.class) {
			return new Float(text);
		}
		if (clazz == double.class || clazz == Double.class) {
			return new Double(text);
		}

		return null;
	}

	public void setFieldInfo(String fieldName, FieldInfo fieldInfo) {
		this.fieldName = fieldName;
		this.fieldInfo = fieldInfo;

		setMetaData();
	}

	private void setMetaData() {
		setName(this.fieldName);
		String description = this.fieldInfo.description();
		if (description.length() > 0)
			setTitle(description);
	}

	public void setValue(Object value) {
		if (value != null)
			setText(value.toString());
		else
			setText("");
	}

	public void onKeyDown(Widget sender, char keyCode, int modifiers) {

	}

	public void onKeyPress(Widget sender, char keyCode, int modifiers) {
		isOnKeyUp = false;// 触发了ONKEYPRESS事件，则不在ONKEYUP事件中校验.
		if (!validateOnPress(keyCode))
			DOM.eventPreventDefault(Event.getCurrentEvent());// 禁止输入的非法字符.
	}

	public void onKeyUp(Widget sender, char keyCode, int modifiers) {
		if (isOnKeyUp && !validation())
			setText("");
		isOnKeyUp = true;// 设置需要在ONKEYUP事件中校验.
	}

	public void onFocus(Widget sender) {
		if (validateMsg == null || validateMsg.isHide())
			return;
		// 错误则选中文本内容
		setSelectionRange(0, getText().length());
		validateMsg.hide();
	}

	public void onLostFocus(Widget sender) {
		String text = getText().trim();
		if (text.length() > 0 && !validation()) {
			showValidationMsg(fieldInfo.label() + "格式错误.");
			return;
		}
		String msg = FieldInputUtil.validateByFieldInfo(fieldInfo, text);
		if (msg != null) {
			showValidationMsg(msg);
		}
	}

	private boolean validateOnPress(char key) {
		String text = getText().trim();
		int offset = getCursorPos();
		String text_new = new StringBuffer(text).insert(offset, key).toString();
		Class<?> datatype = fieldInfo.datatype();
		if (datatype == float.class || datatype == Float.class
				|| datatype == double.class || datatype == Double.class) {// 浮点类型的处理
			String regex_1 = "^[-]?+\\d{0,}+$";// e.g. -123 or 123
			String regex_2 = "^[-]?+\\d{1,}+[.]?+\\d{0,}+$";// e.g. -123.4...
			if (text_new.matches(regex_1) || text_new.matches(regex_2)) {
				return true;
			}
		} else {// 字节和整型的处理
			return text_new.matches(REGEX);// 字符串必须符合整型格式
		}
		return false;
	}

	private boolean validation() {
		String text = getText().trim();
		Class<?> datatype = fieldInfo.datatype();
		if (datatype == float.class || datatype == Float.class
				|| datatype == double.class || datatype == Double.class)
			return text.matches(REGEX) || text.matches(REGEX_POINT);
		else
			return text.matches(REGEX);
	}

	private void showValidationMsg(String msg) {
		if (validateMsg == null)
			validateMsg = new ValidationPopupPanel();
		validateMsg.show(this, msg);
	}

	public void validityCheck() throws ValidationException {
		String text = getText().trim();
		if (text.length() > 0 && !validation())
			throw new ValidationException(fieldInfo.label() + "格式错误.");
		String msg = FieldInputUtil.validateByFieldInfo(fieldInfo, text);
		if (msg != null) {
			throw new ValidationException(msg);
		}
	}

}
